﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace MRadio
{
    public partial class FMTunner : UserControl
    {
        #region -- 变量 --
        /// <summary>
        /// 控件宽度
        /// </summary>
        private double CtlWidth;
        /// <summary>
        /// 空间高度
        /// </summary>
        private double CtlHeight;

        /// <summary>
        /// 上次位置
        /// </summary>
        private Point LastTapPoint = new Point(0.0F, 0.0F);
        /// <summary>
        /// 原点
        /// </summary>
        private Point ZeroPoint = new Point(0.0F, 0.0F);

        /// <summary>
        /// 转偏偏角
        /// </summary>
        private const float VECTOR_ANGLE_MIN = -48.0F;
        private const float VECTOR_ANGLE_MAX = 227F;
        private const float VECTOR_ANGLE_STEP = 1;

        /// <summary>
        /// FM频率范围
        /// </summary>
        private float FEQUENCE_MIN;
        private float FEQUENCE_MAX;

        /// <summary>
        /// 当前角度
        /// </summary>
        private float CurrentAngle = VECTOR_ANGLE_MIN;
        /// <summary>
        /// 当前频率
        /// </summary>
        //private float _currentFequences;

        private DateTime antiShockTime;
        /// <summary>
        /// 角度灯列表
        /// </summary>
        private IList<CircleLight> angleElement = new List<CircleLight>();

        /// <summary>
        /// 缓冲池
        /// </summary>
        private IList<bool> buffer = new List<bool>();
        /// <summary>
        /// 抗抖动缓冲区大小
        /// </summary>
        private const int BUFFER_SIZE = 25;
        /// <summary>
        /// 缓冲池计数器
        /// </summary>
        private Timer tm;
        #endregion

        #region -- Public --
        /// <summary>
        /// 频率更改触发的事件。
        /// </summary>
        public event Action<MouseVector> TunnerChanged;
        /// <summary>
        /// 频率更改触发的UI修改完毕。
        /// </summary>
        public event Action TunnerChangeComplated;
        public FMTunner()
        {
            // 为初始化变量所必需
            InitializeComponent();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="frequencyMin"></param>
        /// <param name="frequencyMax"></param>
        public void InitTunner(float frequencyMin, float frequencyMax, int region)
        {
            this.Dispatcher.BeginInvoke(() =>
            {
                this.FEQUENCE_MIN = frequencyMin;
                this.FEQUENCE_MAX = frequencyMax;

                //TouchPan.MouseMove += new MouseEventHandler(TouchPan_MouseMove);
                TouchPan.Tap += new EventHandler<GestureEventArgs>(TouchPan_Tap);
                CtlWidth = TouchPan.Width;
                CtlHeight = TouchPan.Height;
                ZeroPoint = new Point(CtlWidth / 2, CtlHeight / 2);
                tm = new Timer(TimerTick, null, 0, 200);

                SetRadioRegion(region);
                DrawAllVolumeLight();
            });
           
        }

        /// <summary>
        /// 当前频率
        /// </summary>
        public float CurrentFequences
        {
            get
            {
                //(CurrentAngle-VECTOR_ANGLE_MIN)
                float rate = (CurrentAngle - VECTOR_ANGLE_MIN) / (VECTOR_ANGLE_MAX - VECTOR_ANGLE_MIN);
                return rate * (FEQUENCE_MAX - FEQUENCE_MIN) + FEQUENCE_MIN;
            }
            set
            {
                MouseVector vetctor = new MouseVector() { Direction = value > CurrentFequences };
                while (Math.Abs(CurrentFequences - value) > 0.1)
                {
                    FequenceChange(vetctor);
                }
                if (TunnerChangeComplated != null)
                {
                    TunnerChangeComplated();
                }
            }
        }

        /// <summary>
        /// 设置电台区域
        /// </summary>
        /// <param name="region">UnitedStates = 1, Japan = 2,Europe = 3,</param>
        private void SetRadioRegion(int region)
        {
            if (region == 2)
            {
                this.ImgFMin.Source = Global.GetImageByName("76M.png");
                this.ImgFMax.Source = Global.GetImageByName("90M.png");
            }
        }

        #endregion

        #region -- 频率控制 --
        /// <summary>
        /// 绘制所有的灯
        /// </summary>
        private void DrawAllVolumeLight()
        {
            for (float i = VECTOR_ANGLE_MIN; i <= VECTOR_ANGLE_MAX; i += VECTOR_ANGLE_STEP)
            {
                GenerateLightItem(i, Visibility.Collapsed);
            }
        }

        /// <summary>
        /// 触摸板触摸事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TouchPan_Tap(object sender, GestureEventArgs e)
        {
            LastTapPoint = e.GetPosition(TouchPan);
            antiShockTime = DateTime.Now;
        }

        /// <summary>
        /// 手指旋动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TouchPan_MouseMove(object sender, MouseEventArgs e)
        {
            //抗抖动
            var pos = e.GetPosition(TouchPan);
            MouseVector vector = GetsureVector(LastTapPoint, pos);
            if (vector == null)
                return;

            LastTapPoint = pos;

            buffer.Add(vector.Direction);
            if (buffer.Count >= BUFFER_SIZE)
            {
                TimerTick(null);
            }
        }

        /// <summary>
        /// 频率改变。
        /// </summary>
        /// <param name="vector"></param>
        private void FequenceChange(MouseVector vector)
        {
            var angle = CurrentAngle + (vector.Direction ? VECTOR_ANGLE_STEP : 0.0F - VECTOR_ANGLE_STEP);
            if (angle < VECTOR_ANGLE_MIN || angle > VECTOR_ANGLE_MAX)
                return;
            CurrentAngle = angle;
            //System.Diagnostics.Debug.WriteLine(string.Format("O:{0},{1},{2}", CurrentAngle, VECTOR_ANGLE_MIN, VECTOR_ANGLE_MAX));
            SetVolumeLight((int)CurrentAngle, vector.Direction);
        }

        /// <summary>
        /// 返回点所在的象限,如是原点，则返回0；
        /// </summary>
        /// <param name="location"></param>
        private int MesureRegion(Point location, Point zeroPoint)
        {
            #region
            if (location.X == zeroPoint.X && location.Y == zeroPoint.Y)
            {
                return 0;
            }
            if (location.X < zeroPoint.X && location.Y < zeroPoint.Y)
            {
                return 4;
            }
            else if (location.X > zeroPoint.X && location.Y < zeroPoint.Y)
            {
                return 1;
            }
            else if (location.X > zeroPoint.X && location.Y > zeroPoint.Y)
            {
                return 2;
            }
            else
            {
                return 3;
            }
            #endregion
        }

        /// <summary>
        /// 根据角度计算坐标。
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="element"></param>
        /// <returns></returns>
        private Point GetPositionByAngle(float angle, double width, double height)
        {
            double r = width / 2;
            double b = height / 2 - r * Math.Sin(angle);
            double a = r + r * Math.Cos(angle);
            return new Point(a, b);
        }

        /// <summary>
        /// 判断向量
        /// </summary>
        /// <param name="oriP"></param>
        /// <param name="curP"></param>
        private MouseVector GetsureVector(Point oriP, Point curP)
        {
            int region = MesureRegion(curP, ZeroPoint);
            int lastRegion = MesureRegion(oriP, ZeroPoint);

            MouseVector vector = new MouseVector();
            vector.Direction = false;
            if (region == 1 && (curP.X > oriP.X) && (curP.Y > oriP.Y))
            {
                vector.Value = Math.Sqrt((curP.X - oriP.X) * (curP.Y - oriP.Y));
                vector.Direction = true;
            }
            else if (region == 2 && (curP.X < oriP.X) && (curP.Y > oriP.Y))
            {
                vector.Value = Math.Sqrt((oriP.X - curP.X) * (curP.Y - oriP.Y));
                vector.Direction = true;
            }
            else if (region == 3 && (curP.X < oriP.X) && (curP.Y < oriP.Y))
            {
                vector.Value = Math.Sqrt((oriP.X - curP.X) * (oriP.Y - curP.Y));
                vector.Direction = true;
            }
            else if (region == 4 && (curP.X > oriP.X) && (curP.Y < oriP.Y))
            {
                vector.Value = Math.Sqrt((curP.X - oriP.X) * (oriP.Y - curP.Y));
                vector.Direction = true;
            }
            return vector;
        }

        /// <summary>
        /// 缓冲计数器
        /// </summary>
        /// <param name="obj"></param>
        private void TimerTick(object obj)
        {
            if (buffer.Count >= BUFFER_SIZE)
            {
                int counter = buffer.Where(o => o == true).Count();
                buffer.Clear();
                FequenceChange(new MouseVector() { Direction = counter >= BUFFER_SIZE / 2 + 1 });
                if (TunnerChanged != null)
                {
                    //TODO:
                    TunnerChanged(new MouseVector() { Value = CurrentFequences });
                }
            }
        }

        /// <summary>
        /// 频率指示
        /// </summary>
        /// <param name="i">角度</param>
        ///  <param name="direction">方向</param>
        private void SetVolumeLight(float i, bool direction)
        {
            if (i <= VECTOR_ANGLE_MIN && i >= VECTOR_ANGLE_MAX)
                return;
            if (direction)
            {

                var ele = angleElement.Where(o => o.LightAngle <= i).ToList();
                if (ele != null && ele.Count > 0)
                {
                    foreach (var item in ele)
                    {
                        if (item.Visibility == Visibility.Collapsed)
                        {
                            item.Visibility = Visibility.Visible;
                        }
                    }
                }

                GenerateLightItem(i, Visibility.Visible);
            }
            else
            {
                var ele = angleElement.Where(o => o.LightAngle >= i).ToList();
                if (ele != null && ele.Count > 0)
                {
                    foreach (var item in ele)
                    {
                        item.Visibility = Visibility.Collapsed;
                    }
                }
            }
        }
        /// <summary>
        /// 创建单个的指示灯
        /// </summary>
        /// <param name="i"></param>
        private void GenerateLightItem(float i, Visibility visble)
        {
            CircleLight light = new CircleLight();
            light.LightAngle = i;
            light.RenderTransform = new CompositeTransform() { Rotation = i };
            light.RenderTransformOrigin = new Point(0.5, 0.5);
            light.UseLayoutRounding = true;
            Canvas.SetTop(light, 185);
            Canvas.SetLeft(light, 2);
            light.Visibility = visble;
            CanvasLights.Children.Add(light);
            angleElement.Add(light);
        }
        #endregion
    }

    /// <summary>
    /// 鼠标向量
    /// </summary>
    public class MouseVector
    {
        /// <summary>
        /// 方向,true:顺时针 false:逆时针
        /// </summary>
        public bool Direction { get; set; }

        /// <summary>
        /// 向量值
        /// </summary>
        public double Value { get; set; }
    }

}